﻿using System;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;

namespace Gumini.JulaDB.Linq
{
    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    internal static class Utils
    {
        public static string DataRowToString(DataRow row)
        {
            var sb = new StringBuilder();
            sb.Append(row.Table.Columns.Count + " value(s): ");
            sb.Append(string.Join(", ", row.ItemArray));
            return sb.ToString();
        }

        public static string ColumnsToString(DataTable table)
        {
            var sb = new StringBuilder();
            sb.Append(table.Columns.Count + " column(s): ");
            sb.Append(string.Join(", ", table.Columns.Cast<DataColumn>().Select(c => c.ColumnName)));
            return sb.ToString();
        }

        public static bool IsAnonymousType(Type type)
        {
            return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
                && type.IsGenericType && type.Name.Contains("AnonymousType")
                && (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) ||
                    type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))
                && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
        }

        public static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        public static bool IsNumericType(Type type)
        {
            if (type == null)
                return false;

            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Byte:
                case TypeCode.Decimal:
                case TypeCode.Double:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.SByte:
                case TypeCode.Single:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return true;
                case TypeCode.Object:
                    if (IsNullableType(type))
                        return IsNumericType(Nullable.GetUnderlyingType(type));
                    return false;
            }
            return false;
        }

        private static object GetDefault(Type type)
        {
            if (type.IsValueType)
                return Activator.CreateInstance(type);
            return null;
        }

        public static object ConvertTo(Type t, object obj)
        {
            Type u = Nullable.GetUnderlyingType(t);
            if (u != null)
            {
                if (obj == null)
                    return GetDefault(u);
                return Convert.ChangeType(obj, u);
            }
            else
                return Convert.ChangeType(obj, t);
        }
    }
}
